package com.example.web.controller;


import com.example.common.model.ResultObj;
import com.example.common.utils.PublicUtil;
import com.example.security.exception.PrefixNotFoundException;
import com.example.security.ienum.ShiroErrorCode;
import com.example.security.properties.CompanyProperties;
import com.example.security.provider.MobileRedisProvider;
import com.example.security.utils.ShiroUtils;
import com.example.security.utils.ThreadLocalMap;
import com.example.security.utils.jwt.JwtUtils;
import lombok.NonNull;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.io.Serializable;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * @Author: lex
 * @Date: 2018/11/14
 */
@RestController
@RequestMapping("shiro/mp")
@Slf4j
public class UserController {

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Autowired
    private CompanyProperties companyProperties;

    @Autowired
    private MobileRedisProvider mobileRedisProvider;

    @PostMapping("login")
    public ResultObj login(String username, String password) {
        if (StringUtils.isBlank(username) || StringUtils.isBlank(password)) {
            return new ResultObj(407, "用户名或者密码不能为空");
        }
        Subject subject = SecurityUtils.getSubject();
        //封装用户数据
        UsernamePasswordToken token = new UsernamePasswordToken(username, password);
        try {
            subject.login(token);
            Serializable sessionId = ShiroUtils.getSession().getId();
            log.warn("sessionId=[ {} ] ", sessionId);
            String jwtToken = JwtUtils.createJWT(sessionId.toString(), ShiroUtils.getUser().toString(), companyProperties.getShiroRedisSession().getTimeout() * 1000);
            log.warn("========================= 登入成功 =========================");
            return new ResultObj().putData("user", ShiroUtils.getUser())
                    //将sessionId存到请求头Authorization中,
                    //MySessionManager对获得jsessionId进行重写,原本是从cookie中获取,现在从请求头中获得
                    .putData("Authorization", jwtToken);
        } catch (PrefixNotFoundException e) {
            //用户名不存在
            log.error("登入前缀错误:[ {} ]", e.getMessage(), e);
            return new ResultObj(407, e.getMessage());
        } catch (UnknownAccountException e) {
            //用户名不存在
            log.error("用户名不存在", e);
            return new ResultObj(407, "用户名不存在");
        } catch (LockedAccountException e) {
            log.error("管理员锁定/被删除", e);
            return new ResultObj(407, "管理员锁定/被删除");
        } catch (IncorrectCredentialsException e) {
            //用户名不存在
            log.error("密码错误", e);
            return new ResultObj(407, "密码错误");
        } catch (AuthenticationException e) {
            log.error("未知异常", e);
            return new ResultObj(407, e.getMessage());
        }
    }

    @PostMapping("sendCode")
    public ResultObj sendCode(@Validated @NonNull String mobile) {
        mobileRedisProvider.save(mobile);
        return new ResultObj();
    }

    @PostMapping("setSession")
    public ResultObj setSession(String key, String value) {
        if (StringUtils.isBlank(key) || StringUtils.isBlank(value)) {
            return new ResultObj(407, "key或者value不能为空");
        }
        ShiroUtils.setSessionAttribute(key, value);
        return new ResultObj();
    }

    @PostMapping("logout")
    public ResultObj logout() {
        ShiroUtils.logout();
        return new ResultObj();
    }

    @PostMapping("getSession")
    public ResultObj getSession(String key) {
        if (StringUtils.isBlank(key)) {
            return new ResultObj(407, "key不能为空");
        }
        //lex
        return new ResultObj().putData("key", ShiroUtils.getSessionAttribute(key));
    }

    @GetMapping("total")
    public ResultObj total() {
        System.out.println("ShiroUtils.getUser(): " + ShiroUtils.getUser());
        System.out.println("ShiroUtils.getUserId(): " + ShiroUtils.getUserId());
        System.out.println("ShiroUtils.getSession(): " + ShiroUtils.getSession());
        System.out.println("ShiroUtils.getSession().getId()(): " + ShiroUtils.getSession().getId());
        System.out.println("ShiroUtils.getSubject(): " + ShiroUtils.getSubject());
        return new ResultObj();
    }

    @RequiresPermissions(value = {"msg:find1231232134"})
    @GetMapping("total2")
    public ResultObj total2() {
        System.err.println("ShiroUtils.getUser(): " + ShiroUtils.getUser());
        System.err.println("ShiroUtils.getUserId(): " + ShiroUtils.getUserId());
        System.err.println("ShiroUtils.getSession(): " + ShiroUtils.getSession());
        System.err.println("ShiroUtils.getSession().getId()(): " + ShiroUtils.getSession().getId());
        System.err.println("ShiroUtils.getSubject(): " + ShiroUtils.getSubject());
        return new ResultObj();
    }


    @GetMapping("nologinCode")
    public ResultObj nologinCode() {
        ShiroErrorCode errorMsg = (ShiroErrorCode) ThreadLocalMap.get("errorMsg");
        if (PublicUtil.isEmpty(errorMsg)) {
            return new ResultObj(407, "程序出错!");
        }
        new ResultObj(errorMsg.getCode(), errorMsg.getDesc());
        log.error("错误原因为:[{}]", errorMsg.getDesc());
        return new ResultObj(errorMsg.getCode(), errorMsg.getDesc());
    }

    @GetMapping("noAuthCode")
    public ResultObj noAuthCode() {
        return new ResultObj(407, "shiroConfig未授权配置经过的地方");
    }

    @GetMapping("getShiroUser")
    public ResultObj getShiroUser() {
        return new ResultObj().putData("user", ShiroUtils.getUser());
    }

    @GetMapping("setRedis")
    public ResultObj setRedis(String key, String value) {
        redisTemplate.opsForValue().set(key, value);
        return new ResultObj();
    }

    @GetMapping("getRedis")
    public ResultObj getRedis(String key) {
        String o = (String) redisTemplate.opsForValue().get(key);
        return new ResultObj().putData("key", o);
    }
}
